<?php

namespace App\Services;

use RuntimeException;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Encryption\EncryptException;
use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract;

class AESCrypter implements EncrypterContract
{
    /**
     * AES加密算法名
     * 需要和前端配合
     *
     * @var string
     */
    protected $cipher = 'aes-128-cbc';

    /**
     * AES加密key
     *
     * @var string
     */
    protected $key;

    /**
     * AES加密初始化向量
     *
     * @var string
     */
    protected $iv;

    /**
     * 返回一个新AESCrypter实例
     *
     * @param  string  $key
     * @param  string  $cipher
     * @return void
     *
     * @throws \RuntimeException
     */
    public function __construct(string $key, string $iv)
    {
        // 取出key和iv
        $this->key = $key;
        $this->iv = $iv;
    }

    /**
     * 加密给定值
     *
     * @param  mixed  $value
     * @param  bool  $serialize
     * @return string
     *
     * @throws \Illuminate\Contracts\Encryption\EncryptException
     */
    public function encrypt($value, $serialize = true)
    {
        $encrypted = openssl_encrypt($value, $this->cipher, $this->key, 0, $this->iv);
        if ($encrypted === false) {
            throw new EncryptException('Can\'t encrypt the data.');
        }
        return $encrypted;
    }

    /**
     * Decrypt the given value.
     *
     * @param  mixed  $payload
     * @param  bool  $unserialize
     * @return mixed
     *
     * @throws \Illuminate\Contracts\Encryption\DecryptException
     */
    public function decrypt($payload, $unserialize = true)
    {
        // use OPENSSL_ZERO_PADDING
        $original = openssl_decrypt($payload, $this->cipher, $this->key, 0 , $this->iv);
        if ($original === false) {
            throw new DecryptException('Can\'t decrypt the data.');
        }
        return $original;
    }
}
